package com.zs.letcode.trie;

import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;

/**
 * 单词替换
 * 在英语中，我们有一个叫做词根(root)的概念，它可以跟着其他一些词组成另一个较长的单词——我们称这个词为继承词(successor)。例如，词根an，跟随着单词other(其他)，可以形成新的单词another(另一个)。
 * <p>
 * 现在，给定一个由许多词根组成的词典和一个句子。你需要将句子中的所有继承词用词根替换掉。如果继承词有许多可以形成它的词根，则用最短的词根替换它。
 * <p>
 * 你需要输出替换之后的句子。
 * <p>
 *
 * <p>
 * 示例 1：
 * <p>
 * 输入：dictionary = ["cat","bat","rat"], sentence = "the cattle was rattled by the battery"
 * 输出："the cat was rat by the bat"
 * 示例 2：
 * <p>
 * 输入：dictionary = ["a","b","c"], sentence = "aadsfasf absbs bbab cadsfafs"
 * 输出："a a b c"
 * 示例 3：
 * <p>
 * 输入：dictionary = ["a", "aa", "aaa", "aaaa"], sentence = "a aa a aaaa aaa aaa aaa aaaaaa bbb baba ababa"
 * 输出："a a a a a a a a bbb baba a"
 * 示例 4：
 * <p>
 * 输入：dictionary = ["catt","cat","bat","rat"], sentence = "the cattle was rattled by the battery"
 * 输出："the cat was rat by the bat"
 * 示例 5：
 * <p>
 * 输入：dictionary = ["ac","ab"], sentence = "it is abnormal that this solution is accepted"
 * 输出："it is ab that this solution is ac"
 *
 * <p>
 * 提示：
 * <p>
 * 1 <= dictionary.length<= 1000
 * 1 <= dictionary[i].length <= 100
 * dictionary[i]仅由小写字母组成。
 * 1 <= sentence.length <= 10^6
 * sentence仅由小写字母和空格组成。
 * sentence 中单词的总量在范围 [1, 1000] 内。
 * sentence 中每个单词的长度在范围 [1, 1000] 内。
 * sentence 中单词之间由一个空格隔开。
 * sentence没有前导或尾随空格。
 * 相关标签
 * 字典树
 * 数组
 * 哈希表
 * 字符串
 * <p>
 * Python3
 * <p>
 * <p>
 * <p>
 * 作者：力扣 (LeetCode)
 * 链接：https://leetcode-cn.com/leetbook/read/trie/x0cga2/
 * 来源：力扣（LeetCode）
 * 著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。
 *
 * @author madison
 * @description
 * @date 2021/8/6 09:19
 */
public class Chapter3 {

    public static void main(String[] args) {

    }

    private static class Solution {
        /**
         * 方法一：前缀哈希【通过】
         *
         * @param dictionary
         * @param sentence
         * @return
         */
        public String replaceWords(List<String> dictionary, String sentence) {
            Set<String> rootset = new HashSet<>();
            for (String root : dictionary) rootset.add(root);

            StringBuilder ans = new StringBuilder();
            for (String word : sentence.split("\\s+")) {
                String prefix = "";
                for (int i = 0; i <= word.length(); i++) {
                    prefix = word.substring(0, i);
                    if (rootset.contains(prefix)) break;
                }

                if (ans.length() > 0) ans.append(" ");
                ans.append(prefix);
            }
            return ans.toString();
        }

        /**
         * 方法二：前缀树【通过】
         */
        public String replaceWords1(List<String> dictionary, String sentence) {
            TrieNode trie = new TrieNode();
            for (String root : dictionary) {
                TrieNode cur = trie;
                for (char letter : root.toCharArray()) {
                    int index = letter - 'a';
                    if (Objects.isNull(cur.children[index])) {
                        cur.children[index] = new TrieNode();
                    }
                    cur = cur.children[index];
                }
                cur.word = root;
            }

            StringBuilder ans = new StringBuilder();
            for (String word : sentence.split("\\s+")) {
                if (ans.length() > 0) {
                    ans.append(" ");
                }
                TrieNode cur = trie;
                for (char letter : word.toCharArray()) {
                    int index = letter - 'a';
                    if (cur.children[index] == null || cur.word != null) {
                        break;
                    }
                    cur = cur.children[index];
                }
                ans.append(cur.word != null ? cur.word : word);
            }
            return ans.toString();
        }

        /**
         * 方法二-1：前缀树【通过】
         *
         * @param dictionary
         * @param sentence
         * @return
         */
        public String replaceWords2(List<String> dictionary, String sentence) {
            TrieNode trie = new TrieNode();
            for (String dict : dictionary) {
                trie.insert(dict);
            }
            StringBuilder res = new StringBuilder();
            for (String word : sentence.split("\\s+")) {
                if (res.length() > 0) {
                    res.append(" ");
                }
                res.append(trie.find(word));
            }
            return res.toString();
        }

        private class TrieNode {
            TrieNode[] children;
            String word;

            TrieNode() {
                children = new TrieNode[26];
            }

            public void insert(String word) {
                TrieNode node = this;
                char[] str = word.toCharArray();
                for (char c : str) {
                    if (node.children[c - 'a'] == null) {
                        node.children[c - 'a'] = new TrieNode();
                    }
                    node = node.children[c - 'a'];
                }
                node.word = word;
            }

            public String find(String prefix) {
                TrieNode node = this;
                char[] str = prefix.toCharArray();
                for (char c : str) {
                    if (node == null) {
                        break;
                    }
                    //如果当前节点已有词根，那么直接返回该词根
                    //保证每个继承词都是被最短词根替换的
                    if (node.word != null) {
                        return node.word;
                    }
                    node = node.children[c - 'a'];
                }
                //没有在字典中找到该继承词所对应的词根，因此不产生替换
                return prefix;
            }
        }
    }
}
